/*
    SEL - Simple DirectMedia Layer Extension Library
    Copyright (C) 2001 Matej Knopp <knopp@users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef __sel_painter_h__
#define __sel_painter_h__

#include "../base/sdl.h"
#include "../base/rect.h"

namespace SEL
{

class Surface;

//! The virtual table of graphic routines.
/*!
  The routines should not perform any checking. There are separate tables for
  routines with / without locking.
 */
struct GFXTable
{
	void (*putPixel) (Surface *surface, Uint16, Uint16 y, Uint32 color);

	void (*drawHLine) (Surface *surface, Uint16 x, Uint16 y, Uint16 w,
			   Uint32 color);

	void (*drawVLine) (Surface *surface, Uint16 x, Uint16 y, Uint16 h,
			   Uint32 color);
			   
	void (*drawLine) (Surface *surface, Uint16 x1, Uint16 y1, 
			  Uint16 x2, Uint16 y2, Uint32 color);
};

class Painter
{
public:
	//! Drawing mode
	enum 
	{
		ModeSolid = 0,
		ModeBlended,
		ModeLast
	};
	
	//! Create a new painter class.
	/*!
	  Creates a new Painter class with given \a target surface and drawing
	  \a mode. The surface's reference count is increased by one.
	  \note If \a target is NULL, an exception is thrown, unless \a nothrow
	  is true.
	 */
	Painter (Surface *target, int mode = ModeSolid, bool nothrow = false);

	//! Destroy the painter class.
	/*!
	  Destroys the class and decreases the reference count of the target
	  surface (if any).
	 */
	virtual ~Painter ();

	//! Update the current gfx table according to the current surface type
	//! and drawing mode.
	/*!
	  \return true of success, false if the correct gfx table couldn't be
	  set (e.g. invalid surface type or drawing mode).
	 */
	virtual bool updateGFXTable ();

	//! Set the drawing mode.
	/*!
	  \param mode new drawing mode (ModeSolid or ModeBlended)
	 */
	void setMode (int mode);
	
	//! Get the current drawing mode.
	int mode () const			{ return m_mode; }
	
	//! Set the target surface.
	/*!
	  The reference count of the target surface is increased by one.
	 */
	void setTarget (Surface *);
	
	//! Release the target surface.
	/*!
	  The reference count of the target surface is decreased by one.
	 */
	void releaseTarget ();
	
	//! Get the current target surface.
	Surface *target ()			{ return m_target_surface; }

	//! Get the const pointer to the target surface.
	const Surface *target () const		{ return m_target_surface; }
	
	//! Specify whether to perform clipping.
	void setClipping (bool);

	//! Return if clipping is on.
	bool clipping () const			{ return m_clipping; }

	//! Set the clipping rectangle.
	void setClipRect (const Rect &);

	//! Set the current clipping rectangle according to surface clipping
	//! rectangle.
	void retrieveClipRect ();

	//! Set the clipping rectangle to the whole surface.
	void resetClipRect ();

	//! Get the current clipping rectangle.
	Rect & clipRect () 			{ return m_clip_rect; }
	
	//! Get the current clipping rectangle (constant)
	const Rect & clipRect () const		{ return m_clip_rect; }

	//! Set whether the locking and unlocking should be performed
	//! automatically (within each drawing function)
	void setAutoLock (bool);
	
	//! Get whether the automatic locking is on.
	bool autoLock () const			{ return m_auto_lock; }

	//! Set the pixel on given coordinates to specified color.
	void putPixel (Uint16 x, Uint16 y, Uint32 color);

	//! Draw a horizontal line.
	void drawHLine (Uint16 x, Uint16 y, Uint16 w, Uint32 color);

	//! Draw a vertical line.
	void drawVLine (Uint16 x, Uint16 y, Uint16 h, Uint32 color);	

	//! Draw a line.
	void drawLine (Uint16 x, Uint16 y, Uint16 x2, Uint16 y2, Uint32 color);	

	//! Draw a retangle.
	void drawRect (Uint16 x, Uint16 y, Uint16 w, Uint16 h, Uint32 color);
	
	//! Draw a filled rectangle.
	void fillRect (Uint16 x, Uint16 y, Uint16 w, Uint16 h, Uint32 color);

protected:
	GFXTable *m_gfx;
	Surface *m_target_surface;
	int m_mode;

	Rect m_clip_rect;
	Uint16 m_clip_x2;
	Uint16 m_clip_y2;
	
	bool m_clipping;
	bool m_auto_lock;

	static GFXTable m_gfx_tables [2][2][4]; // [mode][locking][depth]
};

}; // namespace SEL

#endif // __sel_painter_h__
